package com.mioto.ld.communication.mqtt;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.gson.*;
import com.mioto.ld.communication.CommunicationCache;
import com.mioto.ld.communication.mqtt.protocol.model.*;
import com.mioto.ld.communication.mqtt.protocol.model.server.*;
import com.mioto.ld.communication.websocket.model.WsAttributeSetBody;
import com.mioto.ld.communication.websocket.model.WsRecMessage;
import com.mioto.ld.module.network.model.Network;
import com.mioto.ld.communication.mqtt.protocol.model.ReplyStatusEnum;
import com.mioto.ld.utils.SpringBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;

import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author mioto-qinxj
 * @date 2024/5/6
 * @desc
 */
@Slf4j
public class MqttHelper {

    /**
     * 客户端列表
     */
    public static ConcurrentHashMap<Integer, MqttClientConnect> mqttClients = new ConcurrentHashMap(4);

    private static ConcurrentHashMap<String, MqttClientConnect> deviceConnects = new ConcurrentHashMap(4);

    /**
     * mqtt启动连接
     * @param network
     */
    public static void start(Network network){
        try {
            MqttClientConnect mqttClientConnect = new MqttClientConnect();
            mqttClientConnect.setMqttClientId(network.getId());
            String host = "tcp://" + network.getIp() + ":" + network.getPort();
            mqttClientConnect.setMqttClient(host, network.getClientId(), network.getUserName(), network.getPassword(), new MqttClientCallback(network.getId()));
            String subTopic = StrUtil.format("/{}/{}{}",network.getUserName(), network.getPassword(),network.getSubAddress());
            mqttClientConnect.sub(subTopic);
            mqttClients.put(network.getId(), mqttClientConnect);
            log.info("{}--连接成功,订阅主题--{}", network.getClientId(), subTopic);
        } catch (MqttException e) {
           log.error("mqtt连接失败",e);
        }
    }

    /**
     * 属性设置
     */
    public static void controlAttributeSet(WsRecMessage recMessage){
        WsAttributeSetBody attributeSetBody = (WsAttributeSetBody) recMessage.getBody();
        String sn = attributeSetBody.getSn();
        Message message = buildMessage(ServerMtype.SERVER_PARAM_CONFIG,sn);
        AttributeSetPayload attributeSetPayload = new AttributeSetPayload();
        attributeSetPayload.setAttribute(attributeSetBody.getAttributes());
        attributeSetPayload.setPtype(PType.SERVER_ATTRIBUTE_SET);
        message.getMessageBody().setPayload(attributeSetPayload);
        Gson gson = new GsonBuilder().registerTypeAdapter(Payload.class, new JsonSerializer<Payload>() {
            @Override
            public JsonElement serialize(Payload message, Type type, JsonSerializationContext jsonSerializationContext) {
                AttributeSetPayload payload = (AttributeSetPayload) message;
                return payload.toJson();
            }
        }).create();
        MqttClientConnect mqttClientConnect = getMqttConnect(sn);
        if (ObjectUtil.isNotNull(mqttClientConnect)) {
            mqttClientConnect.pub(sn,gson.toJson(message));
            SpringBeanUtil.getBean(CommunicationCache.class).put(sn,PType.SERVER_ATTRIBUTE_SET,recMessage.getClientId());
        }
    }

    /**
     * 远程关机
     */
    public static boolean control(String sn, Payload payload){
        Message message = buildMessage(ServerMtype.SERVER_CONTROL,sn);
        MqttClientConnect mqttClientConnect = getMqttConnect(sn);
        if (ObjectUtil.isNotNull(mqttClientConnect)) {
            JSONObject jsonObject = JSONUtil.parseObj(message,new JSONConfig().setOrder(true));
            jsonObject.getJSONObject("messageBody").set("payload",payload);
            mqttClientConnect.pub(sn,jsonObject.toString());
            return true;
        }
        return false;
    }

    /**
     * 定时任务设置
     */
    public static void timedTaskSet(String sn, Payload payload){
        Message message = buildMessage(ServerMtype.SERVER_PARAM_CONFIG,sn);
        MqttClientConnect mqttClientConnect = getMqttConnect(sn);
        if (ObjectUtil.isNotNull(mqttClientConnect)) {
            log.info("===========同步定时任务到设备 - {}==========",sn);
            JSONObject jsonObject = JSONUtil.parseObj(message);
            jsonObject.getJSONObject("messageBody").set("payload",payload);
            mqttClientConnect.pub(sn,jsonObject.toString());
        }
    }


    /**
     * 服务端回复消息到设备
     */
    public static void reply(Integer mqttClientId,String sn,ReplyStatusEnum replyStatusEnum){
        Message message = buildMessage(ServerMtype.SERVER_REPLY,sn);
        ReplyPayload payload = new ReplyPayload();
        payload.setStatusCode(replyStatusEnum.getStatusCode());
        payload.setStatusDescription(replyStatusEnum.getStatusDescription());
        message.getMessageBody().setPayload(payload);
        getClient(mqttClientId).pub(sn,new Gson().toJson(message));
    }

    public static MqttClientConnect getClient(Integer clientId){
        return mqttClients.get(clientId);
    }

    public static int size(){
        return deviceConnects.size();
    }
    public static boolean containsSn(String sn){
        return deviceConnects.containsKey(sn);
    }

    public static void remove(String sn){
         deviceConnects.remove(sn);
    }

    /**
     * 保存设备通讯的mqtt客户端id
     * @param sn
     * @param clientId
     */
    public static void putDeviceConnects(String sn,Integer clientId){
        deviceConnects.put(sn,mqttClients.get(clientId));
    }

    public static MqttClientConnect getMqttConnect(String sn){
        return  deviceConnects.get(sn);
    }

    private static Message buildMessage(Integer mtype,String sn){
        Message message = new Message();
        message.setMtype(mtype);
        message.setSn(sn);
        MessageBody messageBody = new MessageBody();
        message.setMessageBody(messageBody);
        return message;
    }
}
